package com.apes.scm.voucher.service.builder;

import com.apes.framework.api.SpringManager;
import com.apes.framework.plugin.express.FuncAlias;
import com.apes.framework.util.LogicalUtil;
import com.apes.scm.account.account.model.InventoryMode;
import com.apes.scm.account.ledger.service.LedgerService;
import com.apes.scm.account.tax.model.Tax;
import com.apes.scm.account.tax.service.TaxService;
import com.apes.scm.invoice.model.Invoice;
import com.apes.scm.invoice.model.InvoiceItem;
import com.apes.scm.invoice.service.InvoiceService;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apes.scm.masterdata.party.service.PartyRoleService;
import com.apes.scm.masterdata.product.model.Product;
import com.apes.scm.voucher.model.Voucher;
import com.apes.scm.voucher.repository.VoucherRepository;
import com.apes.scm.voucher.service.VoucherType;
import com.apes.scm.voucher.service.VoucherUtil;
import com.apes.scm.voucher.service.cost.CostMethod;
import com.apes.scm.voucher.service.ict.Ict;

import java.util.Date;
import java.util.stream.Collectors;

/**
 * 功能：抽象凭证构造器
 *
 * @author xul
 * @create 2018-10-18 10:36
 */
public abstract class AbstractVoucherBuilder implements VoucherBuilder {

    protected String voucherType;

    protected String[] BusinessTypes;

    @Override
    public String[] getBusinessTypes() {
        return BusinessTypes;
    }

    /**
     * 凭证保存
     */
    protected Voucher save(Voucher voucher) {
        if (LogicalUtil.notIn(voucher.getBusinessType(), this.BusinessTypes)) {
            throw new RuntimeException("业务单据类型输入错误！");
        }
        voucher.setState("done");
        voucher.setVoucherType(voucherType);
        voucher.computeAmt(); //汇总
        voucher = SpringManager.getBean(VoucherRepository.class).saveAndFlush(voucher);
        return voucher;
    }

    @Override
    public Voucher writeOff(Voucher voucher) {
        throw new RuntimeException("冲销凭证功能未实现！");
    }

    /**
     * 跨公司/公司间交易：Cross-Company/Inter-company transactions
     */
    protected void crossCompanyTransaction(Voucher voucher) {
        String businessType = voucher.getBusinessType();
        Ict ict = VoucherUtil.getBusinessExecutor(Ict.class, businessType);
        if (ict == null) throw new RuntimeException("业务单据类型：" + businessType + " 没有定义跨公司交易服务！");
        ict.transaction(voucher);
    }

    /**
     * 成本核算/价值评估
     */
    protected void costing(Voucher voucher) {
        String businessType = voucher.getBusinessType();
        CostMethod costMethod = VoucherUtil.getBusinessExecutor(CostMethod.class, businessType);
        if (costMethod == null) throw new RuntimeException("业务单据类型：" + businessType + " 没有定义成本核算方法！");
        costMethod.costing(voucher);
    }


    /*
    * 增加/减少账款：暂估款
    * 采购/返厂
    * */
    protected void changCurrentProvisional(Voucher voucher, int sign) {
        if (!voucher.getInventoryMode().equals(InventoryMode.IM_CONSIGN)) return;
        if (LogicalUtil.notIn(this.voucherType, VoucherType.SUPPLIER_PURCHASE, VoucherType.SUPPLIER_CONSUME)) return;
        SpringManager.getBean(LedgerService.class).charge(voucher.getCompany(), voucher.getDept(), voucher.getPartner(), voucher.getInventoryMode(),
                voucher.getAccountingMethod(), voucher.getInnerBusinessKey(), voucher.getInnerBusinessType(),
                new Date(), "current_provisional", sign * voucher.getAmtTotal());
    }

    /**
     * 创建账单
     */
    protected void invoiced(Voucher voucher) {
        Invoice invoice = new Invoice();
        invoice.setCreator(voucher.getCreator());
        invoice.setCompany(voucher.getCompany());
        invoice.setPartner(voucher.getPartner());
        invoice.setDept(voucher.getDept());
        invoice.setContract(voucher.getContract());
        invoice.setInventoryMode(voucher.getInventoryMode());
        invoice.setAccountingMethod(voucher.getAccountingMethod());
        invoice.setOriginBusinessType(voucher.getOriginBusinessType());
        invoice.setOrigin(voucher.getOrigin());
        invoice.setSourceBusinessType(voucher.getInnerBusinessType());
        invoice.setSource(voucher.getId());
        invoice.setCustomerExpand(voucher.getCustomerExpand());
        invoice.setInvoiceItems(voucher.getVoucherItems().stream().map(voucherItem -> {
            InvoiceItem invoiceItem = new InvoiceItem();
            invoiceItem.setProduct(voucherItem.getProduct());
            invoiceItem.setPriceUnit(voucherItem.getPriceUnit());
            invoiceItem.setQty(voucherItem.getProductQty());
            invoiceItem.setUom(voucherItem.getUom());
            invoiceItem.setTax(voucherItem.getTax());
            invoiceItem.setOriginItemId(voucherItem.getOriginItemId());
            invoiceItem.setSourceItemId(String.valueOf(voucherItem.getId()));
            return invoiceItem;
        }).collect(Collectors.toSet()));
        SpringManager.getBean(InvoiceService.class).save(invoice);
    }

    /**
     * 销项税
     */
    protected Tax getSaleTax(PartyRole company, Product product) {
        return SpringManager.getBean(TaxService.class).getSaleTax(company, product);
    }

    /**
     * 进项税
     */
    protected Tax getPurchaseTax(PartyRole company, PartyRole supplier, Product product) {
        return SpringManager.getBean(TaxService.class).getPurchaseTax(company, supplier, product);
    }

    /*
     * 刷新partyRole
     * */
    private PartyRole loadPartyRole(String id) {
        return SpringManager.getBean(PartyRoleRepository.class).findOne(id);
    }

    /**
     * 公司
     */
    public PartyRole getCompany(PartyRole owner) {
        owner = loadPartyRole(owner.getId());
        PartyRole company = SpringManager.getBean(PartyRoleService.class).findByPartyAndRole(owner.getParty().getId(), "Company");
        if (company == null) throw new RuntimeException("内部公司：" + owner.getName() + " 没有定义公司角色！");
        return company;
    }

    /**
     * 客户
     */
    @FuncAlias(name = "getCustomer")
    public PartyRole getCustomer(PartyRole owner) {
        owner = loadPartyRole(owner.getId());
        PartyRole customer = SpringManager.getBean(PartyRoleService.class).findByPartyAndRole(owner.getParty().getId(), "Customer");
        if (customer == null) throw new RuntimeException("内部公司：" + owner.getName() + " 没有定义客户角色！");
        return customer;
    }

    /**
     * 客户
     */
    @FuncAlias(name = "getCustomerById")
    public PartyRole getCustomerById(String id) {
        PartyRole owner = loadPartyRole(id);
        PartyRole customer = SpringManager.getBean(PartyRoleService.class).findByPartyAndRole(owner.getParty().getId(), "Customer");
        if (customer == null) throw new RuntimeException("内部公司：" + owner.getName() + " 没有定义客户角色！");
        return customer;
    }

    /**
     * 人员
     */
    @FuncAlias(name = "getPerson")
    public PartyRole getPerson(PartyRole owner) {
        owner = loadPartyRole(owner.getId());
        PartyRole person = SpringManager.getBean(PartyRoleService.class).findByPartyAndRole(owner.getParty().getId(), "Employee");
        if (person == null) throw new RuntimeException("内部公司：" + owner.getName() + " 没有定义人员角色！");
        return person;
    }

    /**
     * 人员
     */
    @FuncAlias(name = "getPersonById")
    public PartyRole getPersonById(String id) {
        PartyRole owner = loadPartyRole(id);
        PartyRole person = SpringManager.getBean(PartyRoleService.class).findByPartyAndRole(owner.getParty().getId(), "Employee");
        if (person == null) throw new RuntimeException("内部公司：" + owner.getName() + " 没有定义人员角色！");
        return person;
    }

    /**
     * 供应商
     */
    @FuncAlias(name = "getSupplier")
    public PartyRole getSupplier(PartyRole owner) {
        owner = loadPartyRole(owner.getId());
        PartyRole supplier = SpringManager.getBean(PartyRoleService.class).findByPartyAndRole(owner.getParty().getId(), "Supplier");
        if (supplier == null) throw new RuntimeException("内部公司：" + owner.getName() + " 没有定义供应商角色！");
        return supplier;
    }

    /**
     * 供应商
     */
    @FuncAlias(name = "getSupplierById")
    public PartyRole getSupplierById(String id) {
        PartyRole owner = loadPartyRole(id);
        PartyRole supplier = SpringManager.getBean(PartyRoleService.class).findByPartyAndRole(owner.getParty().getId(), "Supplier");
        if (supplier == null) throw new RuntimeException("内部公司：" + owner.getName() + " 没有定义供应商角色！");
        return supplier;
    }

}
